import {
  Body,
  Controller,
  Get,
  Module,
  Param,
  Post,
  Request,
  UseInterceptors,
} from "@nestjs/common";
import { PrismaClient } from "@prisma/client";
import { FastifyRequest } from "fastify";
import { WebResult } from "src/common/web.result";
import { LoginInterceptor } from "src/user/interceptor/login.interceptor";
import { UserTokenService } from "src/user/token.service";
import { ArticleTagCreateDTO } from "./dto/tag-create.dto";
import { ArticleAddTagDTO } from "./dto/article-add-tag.dto";
import { UserModule } from "src/user/user.module";

@Controller("/article/tag")
export class ArticleTagController {
  constructor(
    private readonly prisma: PrismaClient,
    private readonly userTokenService: UserTokenService,
  ) {}

  /**
   * 创建标签
   * @description 通过请求体中的数据创建一个新的标签。需要用户登录。
   * @param request FastifyRequest - Express式样的请求对象，包含HTTP请求的详细信息。
   * @param tagDTO ArticleTagCreateDTO - 创建标签的数据传输对象，包含标签的名称和描述。
   * @returns Promise<WebResult> - 创建成功返回成功的WebResult，否则返回失败的WebResult。
   */
  @Post(["/", "/create"])
  @UseInterceptors(LoginInterceptor)
  async createTag(
    @Request() request: FastifyRequest,
    @Body() tagDTO: ArticleTagCreateDTO,
  ) {
    const uid = this.userTokenService.getUserIDFromRequest(request);
    try {
      const tag = await this.prisma.article_tag.create({
        data: {
          creator_id: uid,
          name: tagDTO.name,
          description: tagDTO.description,
        },
      });
      if (!tag) {
        return WebResult.failure(undefined, "create article tag failed");
      }
      return WebResult.success(undefined, "标签创建成功");
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "内部错误");
    }
  }

  @Post(["/add", "/article/add"])
  @UseInterceptors(LoginInterceptor)
  async articleAddTag(
    @Request() request: FastifyRequest,
    @Body() addDTO: ArticleAddTagDTO,
  ) {
    const uid = this.userTokenService.getUserIDFromRequest(request);
    try {
      const article = await this.prisma.article.findUnique({
        select: {
          publisher_id: true,
        },
        where: {
          id: addDTO.article_id,
        },
      });
      if (!article) {
        return WebResult.failure(undefined, "不存在的文章");
      } else if (article.publisher_id !== uid) {
        return WebResult.failure(undefined, "没有权限");
      }
      const relation = await this.prisma.article_tag_relation.create({
        data: {
          article_id: addDTO.article_id,
          tag_id: addDTO.tag_id,
        },
      });
      if (!relation) {
        return WebResult.failure(undefined, "标签添加失败");
      }
      return WebResult.success(undefined, "标签添加成功");
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "内部错误");
    }
  }

  /**
   * 根据标签ID获取标签信息
   * @param id 标签的ID，字符串形式
   * @returns 返回一个包含标签信息的WebResult对象
   */
  @Get(["/:id", "/id/:id"])
  async getArticleTagByID(@Param("id") id: string) {
    try {
      const tagID = parseInt(id);
      if (isNaN(tagID)) {
        return WebResult.failure(undefined, "id is not a number");
      }
      console.log(tagID);
      const tag = await this.prisma.article_tag.findUnique({
        select: {
          id: true,
          creator_id: true,
          name: true,
          description: true,
        },
        where: {
          id: tagID,
        },
      });
      return WebResult.success(tag);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article tag");
    }
  }

  /**
   * 根据文章ID获取关联的标签ID列表
   * @param id 文章的ID，字符串形式
   * @returns 返回一个包含标签ID数组的WebResult对象
   */
  @Get(["/article/:id", "/article/id/:id"])
  async getTagIDsByArticleID(@Param("id") id: string) {
    try {
      const articleID = parseInt(id);
      if (isNaN(articleID)) {
        return WebResult.failure(undefined, "id is not a number");
      }
      const relationArray = await this.prisma.article_tag_relation.findMany({
        select: {
          tag_id: true,
        },
        where: {
          article_id: articleID,
        },
      });
      const ids = new Array(relationArray.length);
      for (let i = 0; i < relationArray.length; i++) {
        ids[i] = relationArray[i].tag_id;
      }
      return WebResult.success(ids);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get tag id");
    }
  }

  /**
   * 根据标签名称搜索标签
   * @param name 标签名称
   * @returns 返回一个包含搜索结果的标签列表的WebResult对象
   */
  @Get(["/search/:name", "/search/name/:name"])
  async searchArticleTagsByName(@Param("name") name: string) {
    try {
      const tags = await this.prisma.article_tag.findMany({
        select: {
          id: true,
          creator_id: true,
          name: true,
          description: true,
          create_time: true,
        },
        where: {
          name: {
            contains: name,
          },
        },
      });
      return WebResult.success(tags);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article tags");
    }
  }

  /**
   * 根据标签ID获取关联的文章ID列表
   * @param id 标签的ID，字符串形式
   * @returns 返回一个包含文章ID数组的WebResult对象
   */
  @Get([
    "/:id/article/id",
    "/:id/article/ids",
    "/id/:id/article/id",
    "/id/:id/article/ids",
  ])
  async getArticleIDsByTagID(@Param("id") id: string) {
    try {
      const tagID = parseInt(id);
      if (isNaN(tagID)) {
        return WebResult.failure(undefined, "id is not a number");
      }
      const relationArray = await this.prisma.article_tag_relation.findMany({
        select: {
          article_id: true,
        },
        where: {
          tag_id: tagID,
        },
      });
      const ids = new Array(relationArray.length);
      for (let i = 0; i < relationArray.length; i++) {
        ids[i] = relationArray[i].article_id;
      }
      return WebResult.success(ids);
    } catch (e) {
      console.error(e);
      return WebResult.failure(undefined, "failed to get article id");
    }
  }
}

@Module({
  imports: [UserModule],
  controllers: [ArticleTagController],
})
export class ArticleTagModule {}
